using System.Diagnostics.CodeAnalysis;
using KinonekoSoftware.Studio.Pages.Galleries.Abilities;
using KinonekoSoftware.Studio.Pages.Galleries.Filters;

namespace KinonekoSoftware.Studio.Pages.Galleries
{
    [SuppressMessage("ReSharper", "InlineTemporaryVariable")]
    public sealed partial class InstanceGalleryViewModel2 : TabViewModelCore
    {

        //-------------------------------------------------
        //
        //          ReadOnly Fields
        //
        //-------------------------------------------------
        internal readonly InstanceCacheEngine  EngineOfInstance;
        private readonly  CatalogGalleryFilter _FilterOfCatalog;
        private readonly  KeywordGalleryFilter _FilterOfKeyword;
        private readonly  KeywordEngine        _EngineOfKeyword;
        private readonly  List<InstanceCache>  _FinalResult;
        private readonly  RepositoryRuntime    _runtime;


        //-------------------------------------------------
        //
        //          Fields
        //
        //-------------------------------------------------
        private IGalleryFilter    _filter;
        private GalleryScraffolds _gallery;
        private InstanceCatalog   _catalog;
        private InstanceCache     _instance;
        private int               _pageIndex;
        private bool              _isEditPaneOpen;
        private bool              _isKeywordPaneOpen;

        //-------------------------------------------------
        //
        //          Constructors
        //
        //-------------------------------------------------
        public InstanceGalleryViewModel2()
        {
            _runtime          = Ioc.Get<RepositoryRuntime>();
            EngineOfInstance = _runtime.GetEngine<InstanceCacheEngine>();
            _EngineOfKeyword  = _runtime.GetEngine<KeywordEngine>();
            _FilterOfCatalog  = new CatalogGalleryFilter(_runtime.Repository, this);
            _FilterOfKeyword  = new KeywordGalleryFilter(_EngineOfKeyword, _runtime.Repository, this);
            _FinalResult      = new List<InstanceCache>(32);

            Filters = new ObservableCollection<IGalleryFilter>();


            NewInstanceCommand          = CreateCommand(DoNewInstanceCommand);
            SaveInstanceCommand         = CreateCommand<InstanceCache>(DoSaveInstanceCommand);
            OpenNotionCommand           = CreateCommand<InstanceCache>(DoOpenNotionCommand);
            OpenStoryCommand            = CreateCommand<InstanceCache>(DoOpenStoryCommand);
            LockOrUnlockInstanceCommand = CreateCommand<InstanceCache>(DoLockOrUnlockInstanceCommand);
            QuikEditInstanceCommand     = CreateCommand<InstanceCache>(DoQuikEditInstanceCommand);
            EditInstanceCommand         = CreateCommand<InstanceCache>(DoEditInstanceCommand);
            RemoveInstanceCommand       = CreateCommand<InstanceCache>(DoRemoveInstanceCommand);
        }

        //-------------------------------------------------
        //
        //          Private Methods
        //
        //-------------------------------------------------

        private int GetPageBy()
        {
            var pageBy = Math.Clamp(PageBy, 50, 250);

            if (pageBy != PageBy)
            {
                PageBy = pageBy;
            }

            return pageBy;
        }

        private ICollection<InstanceCache> GetDataSource(InstanceCatalog catalog)
        {
            if (catalog.UseCustomType)
            {
                return EngineOfInstance.GetCustomIndexers(catalog.CustomType);
            }

            return EngineOfInstance.Get(catalog.Type);
        }

        private IEnumerable<InstanceCache> BuildSortExpression(ICollection<InstanceCache> collection)
        {
            return SortBy switch
            {
                SortBy.Descending_Name         => collection.OrderByDescending(x => x.Name),
                SortBy.Ascending_CreateTime    => collection.OrderBy(x => x.TimeOfCreated),
                SortBy.Descending_CreateTime   => collection.OrderByDescending(x => x.TimeOfCreated),
                SortBy.Ascending_ModifiedTime  => collection.OrderBy(x => x.TimeOfModified),
                SortBy.Descending_ModifiedTime => collection.OrderByDescending(x => x.TimeOfModified),
                _                              => collection.OrderBy(x => x.Name),
            };
        }


        private void OnGalleryChanged(GalleryScraffolds oldItem, GalleryScraffolds newItem)
        {
            //
            //
            oldItem?.ClearParent();

            //
            //
            Filters.Clear();
            Filters.Add(_FilterOfCatalog);
            Filters.AddMany(newItem.Filters);
            Filters.Add(_FilterOfKeyword);

            //
            //
            newItem.SetParent(this);

            //
            //
            _filter = Filters.FirstOrDefault();
            RaiseUpdated(nameof(Filter));
        }

        //-------------------------------------------------
        //
        //          Override Methods
        //
        //-------------------------------------------------
        protected override void OnStart()
        {
            _FilterOfCatalog.Initialize();
            _FilterOfKeyword.Initialize();
            base.OnStart();
        }

        protected override void OnStop()
        {
            _mapByEnum.Clear();
            _mapByString.Clear();
            base.OnStop();
        }

        //-------------------------------------------------
        //
        //          Internal Or Public Methods
        //
        //-------------------------------------------------
        
        internal void OpenGallery(InstanceCatalog catalog)
        {
            var newValue = GetGalleryItem(catalog);
            var oldValue = _gallery;
            
            //
            //
            OnGalleryChanged(oldValue, newValue);

            //
            //
            Gallery = newValue;
            
            
            InvalidateDataSource(catalog);
        }
        
        internal void InvalidateDataSource(InstanceCatalog catalog)
        {
            //
            //
            _catalog = catalog;


            //
            //
            var original  = GetDataSource(catalog);
            var filter    = GetFilter();
            var firstWalk = filter.Filter(original, SearchBy);
            var pageBy    = GetPageBy();

            //
            // 这是一个完全刷新的方法，调用该方法之后PageIndex会重置。
            PageIndex = 1;
            PageCount = (firstWalk.Count + pageBy - 1) / pageBy;


            //
            // 先排序
            _FinalResult.AddMany(BuildSortExpression(firstWalk), true);

            //
            // 再分页
            Paging(PageIndex);
        }

        internal void ReloadDataSources()
        {
            //
            //
            InvalidateDataSource(_catalog ?? _FilterOfCatalog.Catalog);
        }

        internal void Paging(int index)
        {
            var pageBy = GetPageBy();
            var skip   = (index - 1) * pageBy;
            var paging = Math.Min(_FinalResult.Count - skip, pageBy);


            var iterator = _FinalResult.Skip(skip)
                                       .Take(paging);


            if (Gallery is not null)
            {
                Gallery.Collection.AddMany(iterator, true);
                Gallery.Selected = Gallery.Collection.FirstOrDefault();
            }
        }

        internal void OnGallerySelectionChanged(InstanceCache value)
        {
            //
            // 当Gallery中选择了新的元素时，由Gallery发起选择更改通知。
            // 告诉 InstanceCatalogViewModel当前选择的设定已经发生变化。
            _instance = value;
        }


        public bool CanPreviousPage() => PageIndex > 1;
        public bool CanNextPage()     => PageCount >= PageIndex + 1;

        
        
        //-------------------------------------------------
        //
        //          Properties
        //
        //-------------------------------------------------


        public SortBy SortBy    { get; set; }
        public string SearchBy  { get; set; }
        public int    PageBy    { get; set; }
        public int    PageCount { get; set; }

        public int PageIndex
        {
            get => _pageIndex;
            set => SetValue(ref _pageIndex, value);
        }

        public GalleryScraffolds Gallery
        {
            get => _gallery;
            set => SetValue(ref _gallery, value);
        }


        public bool IsEditPaneOpen
        {
            get => _isEditPaneOpen;
            set
            {
                if (_instance is null)
                {
                    SetValue(ref _isEditPaneOpen, false);
                    return;
                }

                SetValue(ref _isEditPaneOpen, value);
            }
        }
        
        public bool IsKeywordPaneOpen
        {
            get => _isKeywordPaneOpen;
            set => SetValue(ref _isKeywordPaneOpen, value);
        }



        public ObservableCollection<IGalleryFilter> Filters { get; }



    }
}